home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue62 / Alfresco / AANoMem.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2000-09-02  |  11.5 KB  |  429 lines

  1. {*********************************************************}
  2. {* AANoMem                                               *}
  3. {* Copyright (c) Julian M Bucknall 2000                  *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco: Routines that use no heap        *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AANoMem;
  14.  
  15. interface
  16.  
  17. uses
  18.   Windows;
  19.  
  20. {===memory comparison===}
  21. function aaCompareMem(aSrc   : pointer;
  22.                       aLen   : integer;
  23.                       aValue : byte) : boolean;
  24.  
  25. {===PChar routines===}
  26. function aaStrPas(aSrc : PChar) : shortstring;
  27. function aaByteAsHexZ(aDest : PChar; B : byte) : PChar;
  28. function aaPointerAsHexZ(aDest : PChar; P : pointer) : PChar;
  29.  
  30. {===registry routines===}
  31. function aaReadRegistryInt(aKey     : PChar;
  32.                            aValue   : PChar;
  33.                            aDefault : integer) : integer;
  34.  
  35. function aaReadRegistryString(aDest    : PChar;
  36.                               aDestSize: DWORD;
  37.                               aKey     : PChar;
  38.                               aValue   : PChar;
  39.                               aDefault : PChar) : PChar;
  40.  
  41. {===logging routines===}
  42. procedure aaLogOpen(var aLog     : System.Text;
  43.                   const aLogName : shortstring);
  44. procedure aaLogClose(var aLog : System.Text);
  45. procedure aaLogWriteBuffer(var aLog : System.Text;
  46.                            aBuffer : pointer; aBufLen : integer);
  47.  
  48. implementation
  49.  
  50. var
  51.   LogLock  : TRTLCriticalSection;
  52.   FirstLog : boolean;
  53.  
  54. {===memory comparison================================================}
  55. function aaCompareMem(aSrc   : pointer;
  56.                       aLen   : integer;
  57.                       aValue : byte) : boolean;
  58. var
  59.   Mem : PChar;
  60.   i   : integer;
  61. begin
  62.   if (aSrc = nil) then
  63.     Result := false
  64.   else if (aLen <= 0) then
  65.     Result := false
  66.   else begin
  67.     Result := true;
  68.     Mem := aSrc;
  69.     for i := 1 to aLen do begin
  70.       if (Mem^ <> char(aValue)) then begin
  71.         Result := false;
  72.         Exit;
  73.       end;
  74.       inc(Mem);
  75.     end;
  76.   end;
  77. end;
  78. {====================================================================}
  79.  
  80.  
  81. {===PChar routines===================================================}
  82. function aaByteAsHexZ(aDest : PChar; B : byte) : PChar;
  83. const
  84.   HexChars : array [0..15] of char = '0123456789abcdef';
  85. begin
  86.   if (aDest <> nil) then begin
  87.     aDest[0] := HexChars[B shr 4];
  88.     aDest[1] := HexChars[B and $F];
  89.     aDest[2] := #0;
  90.   end;
  91.   Result := aDest;
  92. end;
  93. {--------}
  94. function aaPointerAsHexZ(aDest : PChar; P : pointer) : PChar;
  95. var
  96.   L : longint;
  97. begin
  98.   if (aDest <> nil) then begin
  99.     L := longint(P);
  100.     aDest^ := '$';
  101.     inc(aDest);
  102.     aaByteAsHexZ(aDest, L shr 24);
  103.     inc(aDest, 2);
  104.     aaByteAsHexZ(aDest, (L shr 16) and $FF);
  105.     inc(aDest, 2);
  106.     aaByteAsHexZ(aDest, (L shr 8) and $FF);
  107.     inc(aDest, 2);
  108.     aaByteAsHexZ(aDest, L and $FF);
  109.   end;
  110.   Result := aDest;
  111. end;
  112. {--------}
  113. function aaStrPas(aSrc : PChar) : shortstring;
  114. var
  115.   Len : integer;
  116. begin
  117.   Len := lstrlen(aSrc);
  118.   if (Len > 255) then
  119.     Len := 255;
  120.   Result[0] := char(Len);
  121.   Move(aSrc^, Result[1], Len);
  122. end;
  123. {====================================================================}
  124.  
  125.  
  126. {===registry routines================================================}
  127. function aaReadRegistryInt(aKey     : PChar;
  128.                            aValue   : PChar;
  129.                            aDefault : integer) : integer;
  130. var
  131.   Handle     : HKEY;
  132.   ValueType  : DWORD;
  133.   DestSize   : DWORD;
  134. begin
  135.   Result := aDefault;
  136.   if (RegOpenKey(HKEY_CURRENT_USER, aKey, Handle) = 0) then begin
  137.     DestSize := sizeof(integer);
  138.     if (RegQueryValueEx(Handle, aValue, nil,
  139.                         @ValueType, PByte(@Result), @DestSize) = 0) then
  140.       if (ValueType <> REG_DWORD) then
  141.         Result := aDefault;
  142.   end;
  143. end;
  144. {--------}
  145. function aaReadRegistryString(aDest    : PChar;
  146.                               aDestSize: DWORD;
  147.                               aKey     : PChar;
  148.                               aValue   : PChar;
  149.                               aDefault : PChar) : PChar;
  150. var
  151.   Handle     : HKEY;
  152.   ValueType  : DWORD;
  153.   UseDefault : boolean;
  154. begin
  155.   Result := aDest;
  156.   UseDefault := true;
  157.   if (RegOpenKey(HKEY_CURRENT_USER, aKey, Handle) = 0) then
  158.     if (RegQueryValueEx(Handle, aValue, nil,
  159.                         @ValueType, PByte(aDest), @aDestSize) = 0) then
  160.       if (ValueType = REG_SZ) then
  161.         UseDefault := false;
  162.   if UseDefault then
  163.     lstrcpy(aDest, aDefault);
  164. end;
  165. {====================================================================}
  166.  
  167.  
  168. {===logging routines=================================================}
  169. {these const and type blocks are copied from SysUtils, a unit we
  170.  cannot use since its initialization section allocated memory}
  171. const
  172.   fmClosed = $D7B0;
  173.   fmInput  = $D7B1;
  174.   fmOutput = $D7B2;
  175.   fmInOut  = $D7B3;
  176. type
  177.   PTextBuf = ^TTextBuf;
  178.   TTextBuf = array[0..127] of Char;
  179.   TTextRec = packed record
  180.     Handle: Integer;
  181.     Mode: Integer;
  182.     BufSize: Cardinal;
  183.     BufPos: Cardinal;
  184.     BufEnd: Cardinal;
  185.     BufPtr: PChar;
  186.     OpenFunc: Pointer;
  187.     InOutFunc: Pointer;
  188.     FlushFunc: Pointer;
  189.     CloseFunc: Pointer;
  190.     aaHandle : THandle;
  191.     UserData: array[1..28] of Byte;
  192.     Name: array[0..259] of Char;
  193.     Buffer: TTextBuf;
  194.   end;
  195. {--------}
  196. function TextLogOpen(var F : TTextRec): integer;
  197. var
  198.   OpenMode   : Cardinal;
  199.   ShareMode  : Cardinal;
  200.   CreateMode : Cardinal;
  201. begin
  202.   {set the modes that make sense for each type of open}
  203.   case F.Mode of
  204.     fmInput  :
  205.       begin
  206.         OpenMode := GENERIC_READ;
  207.         ShareMode := FILE_SHARE_READ;
  208.         CreateMode := OPEN_EXISTING;
  209.       end;
  210.     fmOutput :
  211.       begin
  212.         OpenMode := GENERIC_WRITE;
  213.         ShareMode := FILE_SHARE_READ;
  214.         CreateMode := CREATE_ALWAYS;
  215.       end;
  216.     fmInOut  :
  217.       begin
  218.         OpenMode := GENERIC_READ or GENERIC_WRITE;
  219.         ShareMode := FILE_SHARE_READ;
  220.         CreateMode := OPEN_EXISTING;
  221.       end;
  222.   else
  223.     {this isn't really necessary; it fools the warning checker though}
  224.     OpenMode := 0;
  225.     ShareMode := 0;
  226.     CreateMode := 0;
  227.   end;
  228.   {open the file}
  229.   F.aaHandle := CreateFile(F.Name, OpenMode, ShareMode, nil,
  230.                            CreateMode, FILE_ATTRIBUTE_NORMAL, 0);
  231.   {if the file could not be opened, return the error}
  232.   if (F.aaHandle = INVALID_HANDLE_VALUE) then begin
  233.     Result := GetLastError;
  234.   end
  235.   {otherwise prepare for I/O}
  236.   else begin
  237.     F.BufPos := 0;
  238.     F.BufEnd := 0;
  239.     Result := 0;
  240.     if (F.Mode = fmInOut) then begin
  241.       {for Append, ensure we're at the end of the file}
  242.       SetFilePointer(F.aaHandle, 0, nil, FILE_END);
  243.       F.Mode := fmOutput;
  244.     end;
  245.   end;
  246. end;
  247. {--------}
  248. function TextLogInOut(var F : TTextRec): integer;
  249. var
  250.   BytesRead : Cardinal;
  251.   BytesWrit : Cardinal;
  252. begin
  253.   Result := 0;
  254.   {read}
  255.   if (F.Mode = fmInput) then begin
  256.     F.BufPos := 0;
  257.     if ReadFile(F.aaHandle, F.Buffer, F.BufSize, BytesRead, nil) then
  258.       F.BufEnd := BytesRead
  259.     else
  260.       Result := GetLastError;
  261.   end
  262.   {write}
  263.   else begin
  264.     if WriteFile(F.aaHandle, F.Buffer, F.BufPos, BytesWrit, nil) then
  265.       if (BytesWrit <> F.BufPos) then
  266.         Result := 101 {disk full?}
  267.       else
  268.         F.BufPos := 0
  269.     else
  270.       Result := GetLastError;
  271.   end;
  272. end;
  273. {--------}
  274. function TextLogFlush(var F : TTextRec): integer;
  275. begin
  276.   {we don't do any flushing: the log file is going to be closed
  277.    pretty soon anyway}
  278.   Result := 0;
  279. end;
  280. {--------}
  281. function TextLogClose(var F : TTextRec): integer;
  282. begin
  283.   {close the file}
  284.   if (F.Mode <> fmClosed) then begin
  285.     if CloseHandle(F.aaHandle) then
  286.       Result := 0
  287.     else
  288.       Result := GetLastError
  289.   end
  290.   else
  291.     Result := 103; {= file not open}
  292. end;
  293. {--------}
  294. procedure AssignLog(var aLog     : System.Text;
  295.                   const aLogName : shortstring);
  296. begin
  297.   with TTextRec(aLog) do begin
  298.     Mode := fmClosed;
  299.     BufSize := sizeof(Buffer);
  300.     BufPtr := @Buffer;
  301.     OpenFunc := @TextLogOpen;
  302.     InOutFunc := @TextLogInOut;
  303.     FlushFunc := @TextLogFlush;
  304.     CloseFunc := @TextLogClose;
  305.     aaHandle := INVALID_HANDLE_VALUE;
  306.     Move(aLogName[1], Name[0], length(aLogName));
  307.     Name[length(aLogName)] := #0;
  308.   end;
  309. end;
  310. {--------}
  311. procedure aaLogOpen(var aLog     : System.Text;
  312.                   const aLogName : shortstring);
  313. begin
  314.   EnterCriticalSection(LogLock);
  315.   try
  316.     AssignLog(aLog, aLogName);
  317.     if FirstLog then
  318.       System.Rewrite(aLog)
  319.     else
  320.       System.Append(aLog);
  321.     try
  322.       if FirstLog then begin
  323.         writeln(aLog, 'Algorithms Alfresco Log');
  324.         writeln(aLog, '-----------------------');
  325.         writeln(aLog);
  326.         FirstLog := false;
  327.       end;
  328.     except
  329.       System.Close(aLog);
  330.       raise;
  331.     end;
  332.   except
  333.     LeaveCriticalSection(LogLock);
  334.     raise;
  335.   end;
  336. end;
  337. {--------}
  338. procedure aaLogClose(var aLog : System.Text);
  339. begin
  340.   try
  341.     System.Close(aLog);
  342.   finally
  343.     LeaveCriticalSection(LogLock);
  344.   end;
  345. end;
  346. {--------}
  347. procedure aaLogWriteBuffer(var aLog : System.Text;
  348.                            aBuffer : pointer; aBufLen : integer);
  349. var
  350.   Line      : array [0..70] of char;
  351.   HexByte   : array [0..2] of char;
  352.   ByteCount : integer;
  353.   B         : PChar;
  354.   i         : integer;
  355.   HexPos    : integer;
  356.   CharPos   : integer;
  357. begin
  358.   {this routine prints a buffer in the usual hex format:
  359. 0----+----1----+----2----+----3----+----4----+----5----+----6----+----7
  360. xx xx xx xx  xx xx xx xx  xx xx xx xx  xx xx xx xx [cccccccccccccccc]
  361.   sixteen bytes to a line}
  362.  
  363.   {initialize the line buffer}
  364.   FillChar(Line, sizeof(Line), ' ');
  365.   Line[70] := #0;
  366.   Line[51] := '[';
  367.   Line[68] := ']';
  368.  
  369.   {output the buffer, 16 bytes at a time}
  370.   B := PChar(aBuffer);
  371.   ByteCount := 0;
  372.   HexPos := 0;
  373.   CharPos := 52;
  374.   for i := 0 to pred(aBufLen) do begin
  375.     {we're adding another byte, so check that we haven't filled up the
  376.      current line}
  377.     if (ByteCount = 16) then begin
  378.       writeln(aLog, Line);
  379.       FillChar(Line[0], 50, ' ');
  380.       FillChar(Line[52], 16, ' ');
  381.       ByteCount := 0;
  382.       HexPos := 0;
  383.       CharPos := 52;
  384.     end;
  385.     {convert the current byte to hex}
  386.     aaByteAsHexZ(HexByte, byte(B[i]));
  387.     {set the hex value and the character}
  388.     Line[HexPos] := HexByte[0];
  389.     Line[HexPos+1] := HexByte[1];
  390.     if (' ' <= B[i]) and (B[i] < #$7F) then
  391.       Line[CharPos] := B[i]
  392.     else
  393.       Line[CharPos] := '.';
  394.     {advance}
  395.     inc(ByteCount);
  396.     inc(HexPos, 3);
  397.     if ((ByteCount and $3) = 0) then
  398.       inc(HexPos);
  399.     inc(CharPos);
  400.   end;
  401.   {write out the last (partial) line}
  402.   writeln(aLog, Line);
  403. end;
  404. {====================================================================}
  405.  
  406.  
  407. {===Initialization/finalization======================================}
  408. procedure InitializeUnit;
  409. begin
  410.   {create the log lock for multithreaded apps}
  411.   InitializeCriticalSection(LogLock);
  412.   FirstLog := true;
  413. end;
  414. {--------}
  415. procedure FinalizeUnit;
  416. begin
  417.   {destroy the log lock}
  418.   DeleteCriticalSection(LogLock);
  419. end;
  420. {--------}
  421. initialization
  422.   InitializeUnit;
  423. {--------}
  424. finalization
  425.   FinalizeUnit;
  426. {====================================================================}
  427.  
  428. end.
  429.